﻿@page "/interactableOverlay"
@using RatScanner.Scan
@using RatScanner.TarkovDev.GraphQL
@using Task = System.Threading.Tasks.Task;
@using TTask = RatScanner.TarkovDev.GraphQL.Task;
@using RatScanner.View;
@using Color = MudBlazor.Color
@using System.Diagnostics;
@using RatScanner.Pages.InteractableOverlay.Services;
@using RatScanner.Pages.InteractableOverlay.Components;
@using SearchResult = RatScanner.Pages.InteractableOverlay.Services.SearchResult;
@inject MenuVM MenuVM
@inject RatScanner.VirtualScreenOffset VirtualScreenOffset
@inject SettingsVM SettingsVM;
@inject IJSRuntime JSRuntime;
@implements IDisposable

<div id="click-away-background" style="position: absolute; width: 100%; height: 100%;"
     onmousedown="if (event.target == this) DotNet.invokeMethodAsync('RatScanner', 'JSHideOverlay')"></div>
<div style="width: 100%; height: 100%;">
    <div style="position: relative; top: 20%; pointer-events: none;">
        <div class="d-flex align-content-center justify-center">
            <div style="width: 40vw; pointer-events: auto;">
                <MudPaper>
                    <MudTextField @ref="_searchTextField" T="string" Variant="Variant.Outlined"
                                  Adornment="Adornment.End" AdornmentIcon="@Icons.Material.Filled.Search"
                                  DebounceInterval="20" OnDebounceIntervalElapsed="ExecuteSearch" @bind-Value="@_searchText">
                    </MudTextField>
                </MudPaper>

                <MudStack Spacing="2" Class="py-2">
                    @for (int _i = 0; _i < _searchResults.Count(); _i++) {
                        int i = _i;
                        SearchResult searchResult = _searchResults.ElementAt(i);
                        
                        @if (searchResult.Data is Item item) {
                            <ItemSearchResult Item="@item" IsExpanded="@(i == 0)" />
                        } 
                        else if (searchResult.Data is TTask task) {
                            <TaskSearchResult Task="@task" 
                                            IsExpanded="@(i == 0)" 
                                            OnMapClick="@((tuple) => OpenMapForObjective(tuple.task, tuple.objective))" />
                        } 
                        @* TODO: Re-enable map search results when MapViewer is fixed
                        else if (searchResult.Data is Map map) {
                            <MapSearchResult Map="@map" OnMapClick="@(() => OpenMapViewer(map))" />
                        }
                        *@
                    }
                </MudStack>
            </div>
        </div>
    </div>
</div>

@* TODO: Re-enable MapViewer when it is fixed
@if (_selectedMap != null) {
    <MapViewer Map="@_selectedMap"
              Task="@_selectedTask"
              Objective="@_selectedObjective"
              ObjectiveZones="@_selectedObjectiveZones"
              OnClose="@CloseMapViewer" />
}
*@

@code {
    private static MudTextField<string> _searchTextField { get; set; } = null!;
    private string _searchText { get; set; } = "";
    private IEnumerable<SearchResult> _searchResults { get; set; } = new List<SearchResult>();
    private readonly SearchService _searchService = new();

    // Map viewer state
    private Map? _selectedMap = null;
    private TTask? _selectedTask = null;
    private ITaskObjective? _selectedObjective = null;
    private List<TaskZone?>? _selectedObjectiveZones = null;

    private async void ExecuteSearch(string value) {
        var sanitizedValue = _searchService.SanitizeSearch(value);
        var results = Enumerable.Empty<SearchResult>();
        results = results.Concat(await _searchService.SearchItemsAsync(sanitizedValue));
        results = results.Concat(await _searchService.SearchTasksAsync(sanitizedValue));
        // TODO: Re-enable map search when MapViewer is fixed
        // results = results.Concat(await _searchService.SearchMapsAsync(sanitizedValue));
        results = results.Where(result => result != null && result.Data != null);
        results = results.OrderBy(result => result.Score).Take(4);
        _searchResults = results;
    }

    private void OpenMapForObjective(TTask task, ITaskObjective objective) {
        // TODO: Re-enable when MapViewer is fixed
        return;
        
        // Get zones from the objective
        ICollection<TaskZone?>? zones = null;
        
        if (objective is TaskObjectiveBasic basicObj) zones = basicObj.Zones;
        else if (objective is TaskObjectiveItem itemObj) zones = itemObj.Zones;
        else if (objective is TaskObjectiveMark markObj) zones = markObj.Zones;
        else if (objective is TaskObjectiveQuestItem questItemObj) zones = questItemObj.Zones;
        else if (objective is TaskObjectiveUseItem useItemObj) zones = useItemObj.Zones;
        
        if (zones == null || !zones.Any()) return;
        
        // Get the first zone with a position
        TaskZone? zone = zones.FirstOrDefault(z => z?.Position != null);
        
        // Find the matching map
        if (zone?.Map?.Id == null) return;
        Map? map = TarkovDevAPI.GetMaps().FirstOrDefault(m => m.Id == zone.Map.Id);
        
        if (map == null) return;
        
        _selectedTask = task;
        _selectedObjective = objective;
        _selectedObjectiveZones = zones.Where(z => z?.Position != null).ToList();
        OpenMapViewer(map);
    }

    private void OpenMapViewer(Map map) {
        _selectedMap = map;
        StateHasChanged();
    }

    private void CloseMapViewer() {
        _selectedMap = null;
        _selectedTask = null;
        _selectedObjective = null;
        _selectedObjectiveZones = null;
        StateHasChanged();
    }

    [JSInvokable]
    public static void JSHideOverlay() {
        BlazorUI.BlazorInteractableOverlay.HideOverlay();
    }

    [JSInvokable]
    public static void JSShowOverlay() {
        _searchTextField.FocusAsync();
        _searchTextField.SelectAsync();
    }

    protected override void OnInitialized() {
        MenuVM.PropertyChanged += PropertyChangeHandler;
    }

    private async void PropertyChangeHandler(object? sender, EventArgs e) {
        await InvokeAsync(() => StateHasChanged());
    }

    public void Dispose() {
        MenuVM.PropertyChanged -= PropertyChangeHandler;
    }
}
